/*

gcc pp.c -lpthread && ./a.out

*/
#include <assert.h>
#include <stdio.h>
#include <pthread.h>

typedef struct sema{
    int value;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}sema;

sema mutex, ping, pong;

void sema_init(sema* s, int value)
{
    s->value = value;
    pthread_cond_init(&s->cond, NULL);
    pthread_mutex_init(&s->mutex, NULL);
}

void P(sema* s)
{
    pthread_mutex_lock(&s->mutex);
    while (s->value <= 0)
        pthread_cond_wait(&s->cond, &s->mutex);

    s->value--;
    pthread_mutex_unlock(&s->mutex);
}

void V(sema* s)
{
    pthread_mutex_lock(&s->mutex);
    pthread_cond_signal(&s->cond);
    s->value++;
    pthread_mutex_unlock(&s->mutex);
}

void* produce(void* arg)
{
    while (1)
    {
        P(&ping);
        P(&mutex);

        printf("ping\n");
        
        V(&mutex);
        V(&pong);
    }
}

void* consume(void* arg)
{
    while (1)
    {
        P(&pong);
        P(&mutex);

        printf("pong\n");
        
        V(&mutex);
        V(&ping);
    }
}

int main(int argc, char** argv)
{
    sema_init(&mutex, 1);
    sema_init(&ping, 1);
    sema_init(&pong, 0);

    pthread_t pid[2];
    pthread_create(pid, NULL, produce, NULL);
    pthread_create(pid+1, NULL, consume, NULL);

    pthread_join(pid[0], NULL);
    pthread_join(pid[1], NULL);
}